#include <iostream>
#include <algorithm>
#include "MusicPlayer.h"
#include "Player.h"
#include "Finder.h"
#include "DurationCounter.h"

//! A functor which is calling Accept() for a media in the list mPlaylist
/*! 
	The functor is used for the for_each algorithm in functions of
	the MusicPlayer which have to iterate through the whole
	playlist.
	The functor applies the Accept() function to every
	MusicMedia. The visitor will be accepted and called.
*/
class Visit : public std::unary_function<MusicMedia*, void>{
public:
	//! CTor of functor Visit
	/*! 
		The CTor of the functor Visit stores
		the passed value in a member.
		\param visit The visitor that will be
		accepted for this media
	*/
	Visit(IVisitor* visit): mVisit(visit){}
	//! operator() overloaded
	/*! 
		The overloaded operator() calls accept
		for its media with the Visitor stored in mVisit.
		\param media The MusicMedia that will accept the visitor
		accepted for this media
	*/
	void operator()(MusicMedia* media){
		media->Accept(mVisit);
	}
private:
	//visitor for the media
	IVisitor* mVisit;
};

void MusicPlayer::AddMedia(MusicMedia* media){
	if (media != 0){
		//add a media
		mPlaylist.push_back(media);
	}
	else{
		//media is invalid
		throw std::exception("MusicPlayer::AddMedia(): Invalid pointer!");
	}
}

void MusicPlayer::RemoveMedia(MusicMedia* media){
	if (media != 0){
		//search for the media to be removed
		TPlaylistIterator found = std::find(mPlaylist.begin(), mPlaylist.end(), media);
		//if it is found, erase it
		if (found != mPlaylist.end()){
			mPlaylist.erase(found);
		}else{
			std::cout << "RemoveMedia: Object not found" << std::endl;
		}
	}
	else{
		//media is invalid
		throw std::exception("MusicPlayer::RemoveMedia(): Invalid pointer!");
	}
}

void MusicPlayer::Play(){
	//create a new Player visitor
	Player play;
	//call Visitor (Accept()) for every element in the playlist
	std::for_each(mPlaylist.begin(), mPlaylist.end(), Visit(&play));
	std::cout << std::endl;
}

void MusicPlayer::printfoundmedia(MusicMedia * media){
	//print name of a media to std::cout
	std::cout << *media->getName() << std::endl;
}

void MusicPlayer::Search(std::string const& search){
	std::cout << "found medias: (search for '" << search << "')" << std::endl;
	//create a new Finder visitor
	Finder find(search);
	//call Visitor (Accept()) for every element in the playlist
	std::for_each(mPlaylist.begin(), mPlaylist.end(), Visit(&find));
	//get the list of all found medias
	TMedia const * media = find.getMedia();
	if (media->size() != 0){
		//print all found medias to std::cout
		std::for_each(media->begin(), media->end(), printfoundmedia);
	}
	else{
		std::cout << "no medias found" << std::endl;
	}
	std::cout << std::endl;
}

TDuration MusicPlayer::GetDuration(std::string const& song) const{
	//create a new DurationCounter visitor
	DurationCounter duration;
	//get the duration for every element in the playlist, if no parameter
	//is passed
	if (song == ""){
		std::for_each(mPlaylist.begin(), mPlaylist.end(), Visit(&duration));
	}
	else{
		//use a Finder to find the media the duration should be found for
		Finder find(song);
		//find the media
		std::for_each(mPlaylist.begin(), mPlaylist.end(), Visit(&find));
		//get the list of all found medias
		TMedia const * media = find.getMedia();
		//get the duartion of the medias
		std::for_each(media->begin(), media->end(), Visit(&duration));
	}
	//return the duration
	return duration.getDuration();
}